/*
 * @Author: wwssaabb
 * @Date: 2021-12-15 11:22:19
 * @LastEditTime: 2021-12-15 15:18:59
 * @FilePath: \handwritten-code\main\并行限制的异步调度器.js
 */


/* 
  实现一个并行限制的异步调度器，保证同时运行的任务最多有两个
*/


class Scheduler {
  constructor(limit = 2) {
    //并发数限制
    this.limit = limit
    //存放未执行的异步函数
    this.queue = []
    //计数器
    this.count = 0
  }

  async add(callback) {
    //这步非常巧妙，这是把resolve放到queue中保存，如果count<limit的异步执行完之后会调用下面的queue.shift()()来执行resolve()，
    //且在状态改变之前queue中的异步会被await阻塞下面的同步代码
    this.count >= this.limit ? await new Promise((resolve) => this.queue.push(resolve)) : null;
    this.count++
    let res = await callback()
    this.count--

    //如果queue中有待执行的异步，则取出调用resolve改变状态
    if (this.queue.length) {
      this.queue.shift()()
    }
    return res
  }
}


/* 
 a.addTask(1000, "1");
 a.addTask(500, "2");
 a.addTask(300, "3");
 a.addTask(400, "4");
 a.addTask(100, "5");
 a.addTask(500, "6");
 a.addTask(600, "7");
 a.addTask(1500, "8");
 a.addTask(2000, "9");
 a.addTask(800, "10");
 的输出顺序是： 2 3 1 5 4 6 7 8 9 10
*/

const scheduler = new Scheduler()

const addTask = (time, order) => {
  scheduler.add(() => new Promise(resolve => setTimeout(() => resolve(order), time)).then(res => console.log(res)))
}

addTask(1000, "1");
addTask(500, "2");
addTask(300, "3");
addTask(400, "4");
addTask(100, "5");
addTask(500, "6");
addTask(600, "7");
addTask(1500, "8");
addTask(2000, "9");
addTask(800, "10");